package main

import (
	"fmt"
	"time"
)

func main() {
	// 默认情况下,管道是双向的
	//var chan1 chan int // 可读可写
	//var chan2 chan<- int //只可以写
	//var chan3 <-chan int // 只可以读
	//send(chan1)
	//recv(chan1)
	//testSelect()
	testRecover()
}

func send(ch chan<- int) {
	for i := 0; i < 10; i++ {
		ch <- i
	}
}

func recv(ch <-chan int) {
	for {
		v, ok := <-ch
		if !ok {
			break
		}
		fmt.Println(v)
	}
}

func testSelect() {
	// 使用select可以解决从管道取数据的阻塞问题

	// 1.定义一个管道 10个数据 int
	intChan := make(chan int, 10)
	for i := 0; i < 10; i++ {
		intChan <- 1
	}
	// 2.定义一个管道 5个数据 string
	strChant := make(chan string, 5)
	for i := 0; i < 5; i++ {
		strChant <- fmt.Sprintf("hello %d", i)
	}

	// 传统的方法便利管道时，如果不关闭会阻塞而导致 deadlock
	// 但是在实际开发中，我们不确定什么时候关闭管道
	// 可以使用select方式解决

	for {
		select {
		// 这里如果intChan一直没有关闭，不会一直阻塞而deadline
		// 会自动到下一个case
		case v := <-intChan:
			fmt.Printf("从intChan读取的数据%d\n", v)
		case v := <-strChant:
			fmt.Printf("从strChan读取的数据%s\n", v)
		default:
			fmt.Println("都取不到了")
			return
		}
	}
}

func testRecover() {
	go func() {
		for i := 0; i < 10; i++ {
			time.Sleep(time.Second)
			fmt.Println("hello world")
		}
	}()

	go func() {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println("aaa")
			}
		}()
		var myMap map[int]string
		myMap[0] = "golang"
		fmt.Println(myMap)
	}()

	time.Sleep(time.Second * 10)
	fmt.Println("ok")
}
